﻿using System;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Routing;
using System.Web.Security;

namespace MvcFlow.StateStores
{
    public class CookieWorkflowStateStore : IWorkflowStateStore
    {
        private readonly IWorkflowHost workflowHost;
        private readonly TimeSpan persistenceTime;
        private readonly bool httpOnly;
        private readonly string prefix;

#pragma warning disable 1998
        public async Task<WorkflowState> Get(RequestContext requestContext, string workflowName)
        {
            var cookie = requestContext.HttpContext.Request.Cookies.Get(GetCookieName(workflowName));

            if (cookie != null)
            {
                var cookieValue = cookie.Value;

                if (!workflowHost.IsDebugging(requestContext))
                {
                    var decryptedData   = MachineKey.Decode(cookieValue, MachineKeyProtection.All);
                    cookieValue         = Encoding.UTF8.GetString(decryptedData);
                }

                return WorkflowState.FromString(cookieValue);
            }

            return null;
        }

        public async Task Put(RequestContext requestContext, WorkflowState workflowState)
        {
            var cookie = requestContext.HttpContext.Request.Cookies.Get(GetCookieName(workflowState.Name));

            if (cookie == null)
            {
                cookie = new HttpCookie(GetCookieName(workflowState.Name))
                {
                    HttpOnly    = httpOnly,
                    Expires     = DateTime.UtcNow + persistenceTime
                };

                requestContext.HttpContext.Response.Cookies.Add(cookie);
            }

            cookie.Value = workflowState.ToString();

            if (!workflowHost.IsDebugging(requestContext))
            {
                cookie.Value = MachineKey.Encode(Encoding.UTF8.GetBytes(cookie.Value), MachineKeyProtection.All);
            }
        }

        public async Task Delete(RequestContext requestContext, WorkflowState workflowState)
        {
            var cookie = requestContext.HttpContext.Request.Cookies.Get(GetCookieName(workflowState.Name));

            if (cookie != null)
            {
                cookie.Expires = DateTime.UtcNow - TimeSpan.FromDays(1.0);
                requestContext.HttpContext.Response.Cookies.Add(cookie);
            }
        }
#pragma warning restore 1998

        private string GetCookieName(string workflowName)
        {
            return (prefix + workflowName).ToLowerInvariant();
        }

        public CookieWorkflowStateStore(IWorkflowHost workflowHost, TimeSpan? persistenceTime = null, bool httpOnly = true, string prefix = "Workflow-")
        {
            this.workflowHost       = workflowHost;
            this.persistenceTime    = persistenceTime ?? TimeSpan.FromDays(1.0);
            this.httpOnly           = httpOnly;
            this.prefix             = prefix;
        }
    
    }
}